﻿using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using YogaDictionary.Common;

namespace YogaDictionary.Model
{
    public static class DataRepo
    {
        private static readonly DatabaseContext Context = new DatabaseContext();

        static DataRepo()
        {
        }

        public static List<Glossary> Glossaries
        {
            get { return Context.Glossaries.Where(p => p.Active).OrderBy(p => p.Name).ToList(); }
        }

        public static List<Definition> Definitions
        {
            get { return Context.Definitions.Where(p => p.Active).Where(p => p.Glossary.Active).ToList(); }
        }

        public static List<Word> Words
        {
            get
            {
                var list = Context.Words
                    .Where(p => p.Active)
                    .Where(p => p.Definition.Active)
                    .Where(p => p.Definition.Glossary.Active)
                    .ToList();
                list.Sort(new WordComparer());
                return list;
            }
        }

        public static List<Description> Descriptions
        {
            get
            {
                return Context.Descriptions
                    .Where(p => p.Active)
                    .Where(p => p.Definition.Active)
                    .Where(p => p.Definition.Glossary.Active)
                    .ToList();
            }
        }

        public static Glossary GetGlossary(long glossaryId)
        {
            return Context.Glossaries.SingleOrDefault(d => d.GlossaryId == glossaryId);
        }

        public static Glossary GetGlossary(string name)
        {
            return Context.Glossaries.SingleOrDefault(d => d.Name == name);
        }

        public static Definition GetDefinition(long definitionId)
        {
            return Context.Definitions.SingleOrDefault(d => d.DefinitionId == definitionId);
        }

        public static Word GetWord(long wordId)
        {
            return Context.Words.SingleOrDefault(d => d.WordId == wordId);
        }

        public static Word GetWord(string value)
        {
            return Context.Words.SingleOrDefault(d => d.Value == value);
        }

        public static Description GetDescription(long descriptionId)
        {
            return Context.Descriptions.SingleOrDefault(d => d.DescriptionId == descriptionId);
        }

        public static long AddGlossary(string name, string author, string description, bool active = true, List<Definition> definitions = null)
        {
            if (name.IsNullOrEmpty())
                throw new ArgumentNullException("name");

            var newGlossary = new Glossary
            {
                Active = active, 
                Name = name, 
                Author = author,
                Description = description,
                Definitions = definitions
            };
            Context.Glossaries.Add(newGlossary);
            SaveChanges();
            return newGlossary.GlossaryId;
        }

        public static long AddDefinition(long glossaryId, bool active = true, List<Word> words = null, List<Description> descriptions = null)
        {
            var glossary = Context.Glossaries.SingleOrDefault(g => g.GlossaryId == glossaryId);
            if (glossary == null)
                throw new ArgumentOutOfRangeException("glossaryId");

            var newDefinition = new Definition
            {
                Active = active,
                GlossaryId = glossaryId,
                Words = words, 
                Descriptions = descriptions
            };
            Context.Definitions.Add(newDefinition);
            SaveChanges();
            return newDefinition.DefinitionId;
        }

        public static long AddWord(long definitionId, string value, bool isPrimary = true, bool active = true)
        {
            if (value.IsNullOrEmpty())
                throw new ArgumentNullException("value");
            if (GetDefinition(definitionId) == null)
                throw new ArgumentOutOfRangeException("definitionId");

            var newWord = new Word
            {
                Active = active,
                DefinitionId = definitionId,
                Value = value,
                IsPrimary = isPrimary
            };
            Context.Words.Add(newWord);
            SaveChanges();
            return newWord.WordId;
        }

        public static long AddDescription(long definitionId, string value, bool isPrimary = true, bool active = true)
        {
            if (value.IsNullOrEmpty())
                throw new ArgumentNullException("value");
            if (GetDefinition(definitionId) == null)
                throw new ArgumentOutOfRangeException("definitionId");

            var newDescription = new Description
            {
                Active = active,
                DefinitionId = definitionId,
                Value = value,
                IsPrimary = isPrimary
            };
            Context.Descriptions.Add(newDescription);
            SaveChanges();
            return newDescription.DescriptionId;
        }

        public static void RemoveGlossary(long glossaryId)
        {
            var glossary = GetGlossary(glossaryId);
            if (glossary == null)
                throw new ArgumentOutOfRangeException("glossaryId");

            Context.Glossaries.Remove(glossary);
            SaveChanges();
        }

        public static void RemoveDefinition(long definitionId)
        {
            var definition = GetDefinition(definitionId);
            if (definition == null)
                throw new ArgumentOutOfRangeException("definitionId");

            Context.Definitions.Remove(definition);
            SaveChanges();
        }

        public static void EnableGlossary(long glossaryId)
        {
            var glossary = GetGlossary(glossaryId);
            if (glossary == null)
                throw new ArgumentOutOfRangeException("glossaryId");
            if (glossary.Active) 
                return;
            glossary.Active = true;
            SaveChanges();
        }

        public static void EnableDefinition(long definitionId)
        {
            var definition = GetGlossary(definitionId);
            if (definition == null)
                throw new ArgumentOutOfRangeException("definitionId");
            if (definition.Active)
                return;
            definition.Active = true;
            SaveChanges();
        }

        public static void EnableWord(long wordId)
        {
            var word = GetGlossary(wordId);
            if (word == null)
                throw new ArgumentOutOfRangeException("wordId");
            if (word.Active)
                return;
            word.Active = true;
            SaveChanges();
        }

        public static void EnableDescription(long descriptionId)
        {
            var description = GetGlossary(descriptionId);
            if (description == null)
                throw new ArgumentOutOfRangeException("descriptionId");
            if (description.Active)
                return;
            description.Active = true;
            SaveChanges();
        }

        public static void DisableGlossary(long glossaryId)
        {
            var glossary = GetGlossary(glossaryId);
            if (glossary == null)
                throw new ArgumentOutOfRangeException("glossaryId");
            if (!glossary.Active)
                return;
            glossary.Active = false;
            SaveChanges();
        }

        public static void DisableDefinition(long definitionId)
        {
            var definition = GetGlossary(definitionId);
            if (definition == null)
                throw new ArgumentOutOfRangeException("definitionId");
            if (!definition.Active)
                return;
            definition.Active = false;
            SaveChanges();
        }

        public static void DisableWord(long wordId)
        {
            var word = GetGlossary(wordId);
            if (word == null)
                throw new ArgumentOutOfRangeException("wordId");
            if (!word.Active)
                return;
            word.Active = false;
            SaveChanges();
        }

        public static void DisableDescription(long descriptionId)
        {
            var description = GetGlossary(descriptionId);
            if (description == null)
                throw new ArgumentOutOfRangeException("descriptionId");
            if (!description.Active)
                return;
            description.Active = false;
            SaveChanges();
        }

        public static void Test()
        {
            GlossaryInitializer.InitializeAll(false);
            DisableGlossary(GetGlossary("Test").GlossaryId);

            //Glossaries.ForEach(g => Log.Debug(g.ToString()));
            //Definitions.ForEach(g => Log.Debug(g.ToString()));
            //Words.ForEach(g => Log.Debug(g.ToString()));
            //Descriptions.ForEach(g => Log.Debug(g.ToString()));
        }

        private static void SaveChanges()
        {
            try
            {
                Context.SaveChanges();
            }
            catch (DbEntityValidationException dbEx)
            {
                foreach (var validationErrors in dbEx.EntityValidationErrors)
                {
                    foreach (var validationError in validationErrors.ValidationErrors)
                    {
                        Log.Debug(
                            "Property: " + validationError.PropertyName + " Error: " + validationError.ErrorMessage);
                    }
                }
                throw;
            }
        }

    }
}
